package main.database;

import com.mongodb.BasicDBObject;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Projections;
import com.mongodb.client.model.Updates;
import com.mongodb.client.result.UpdateResult;
import main.GlobalConfig;
import main.Logman;
import org.bson.Document;
import org.bson.conversions.Bson;

import java.util.ArrayList;
import java.util.List;

public class AccountHelper {
    /**
     * 作用：给定一个uuid（每个user账户都有一个注册时候分配的UUID），查询该uuid是否在数据库中存在
     * @param uuid: 用来查询的uuid
     */
    public static boolean isExistFromUUID(String uuid) {
        if (uuid == null || uuid.isEmpty()) return false;

        MongoCollection<Document> collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfUser);
        return collection.countDocuments(new BasicDBObject("uuid", uuid)) != 0;
    }

    public static boolean isExistFromEmail(String email) {
        MongoCollection<Document> collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfUser);
        return collection.countDocuments(new BasicDBObject("email", email)) != 0;
    }

    /**
     * 作用：给定一个uuid（每个user账户都有一个注册时候分配的UUID），查询该uuid对应的账户是否是admin角色
     * @param uuid: 用来查询的uuid
     */
    public static boolean isAdminFromUUID(String uuid) {
        MongoCollection<Document> collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfUser);
        FindIterable<Document> findIterable = collection.find(new BasicDBObject("uuid", uuid));
        MongoCursor<Document> cursor = findIterable.iterator();
        boolean result = false;
        if (cursor.hasNext()) {
            String role = (String) cursor.next().get("role");
            if (role != null && !role.isEmpty() && role.equals("admin") ) {
                result = true;
            }
        }
        cursor.close();

        return result;
    }

    /**
     * 作用：给定一个昵称，查看该昵称是否在用户数据库中是否存在
     * @param nick
     * @return
     */
    public static boolean isNickExist(String nick) {
        nick = nick.trim();

        MongoCollection<Document> collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfUser);
        FindIterable<Document> findIterable = collection.find(Filters.eq("account", nick));
        MongoCursor<Document> cursor = findIterable.iterator();
        boolean result = false;
        if (cursor.hasNext()) {
            result = true;
        }
        cursor.close();

        return result;
    }

    /**
     * 更新用户的昵称
     * @param uuid，用户的uuid
     * @param oldNick，旧的昵称
     * @param newNick，新的昵称
     */
    public static void updateNick(String uuid, String oldNick, String newNick) {
        MongoCollection<Document> collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfUser);
        Bson filter = Filters.eq("uuid", uuid);
        Bson update = Updates.set("account", newNick);
        UpdateResult updateResult = collection.updateOne(filter, update);
        if (updateResult.getModifiedCount() == 1) {
            //被修改的（老的昵称，如果在用户名字库里，可以释放出来了）
            collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfUserNamePool);
            filter = Filters.eq("name", oldNick);
            update = Updates.set("used", false);
            collection.updateOne(filter, update);

            //如果新的昵称正好和名字库中的一个相同，那么需要置为已用
            filter = Filters.eq("name", newNick);
            update = Updates.set("used", true);
            collection.updateOne(filter, update);
        }
    }

    /**
     * 作用：给定一个uuid（客户端的cookie中会记录，由服务器分配给登录的客户），在数据库中查询该uuid对应的账户名
     * @param uuid: 用来查询的uuid
     */
    public static String getAccountInfoFromUUID(String uuid) {
        MongoCollection<Document> collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfUser);
        FindIterable<Document> findIterable = collection.find(new BasicDBObject("uuid", uuid)).projection(Projections.include("account"));
        MongoCursor<Document> cursor = findIterable.iterator();

        String result = null;
        if (cursor.hasNext()) {
            Document doc = cursor.next();
            result = (String) doc.get("account");
        }
        cursor.close();

        return result;
    }

    /**
     * 取一個用戶的多個字段：account, phone, email, wechat, zhifubao，按次序放在數組中
     * @param uuid
     * @return
     */
    public static String[] getAccountInfosFromUUID(String uuid) {
        MongoCollection<Document> collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfUser);
        FindIterable<Document> findIterable = collection.find(Filters.eq("uuid", uuid));
        MongoCursor<Document> cursor = findIterable.iterator();

        String[] result = null;
        if (cursor.hasNext()) {
            Document doc = cursor.next();
            result = new String[7];

            result[0] = doc.get("account").toString();
            result[1] = doc.get("phone").toString();
            result[2] = doc.get("email").toString();
            result[3] = doc.get("wechat").toString();
            result[4] = doc.get("zhifubao").toString();
            result[6] = doc.get("money").toString();
        }

        return result;
    }

    /**
     * 通过用户的uuid更新该用户的email信息（原来email可以是空）
     * @param uuid
     * @param email
     */
    public static void updateEmailFromUUID(String uuid, String email) {
        MongoCollection<Document> collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfUser);
        Bson filter = new Document("uuid", uuid);
        Bson newValue = new Document("email", email);
        Bson updateOperationDocument = new Document("$set", newValue);
        UpdateResult result = collection.updateOne(filter, updateOperationDocument);
        if (result.getModifiedCount() != 1) {
            Logman.error("更新邮箱错误：" + uuid + " | " + email);
        }
    }

    /**
     * 用户丢失密码后，通过邮箱来更新密码
     * @param email
     * @param password
     */
    public static void updatePasswordFromEmail(String email, String password) {
        MongoCollection<Document> collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfUser);
        Bson filter = new Document("email", email);
        Bson newValue = new Document("password", password);
        Bson updateOperationDocument = new Document("$set", newValue);
        UpdateResult result = collection.updateOne(filter, updateOperationDocument);
        if (result.getModifiedCount() != 1) {
            Logman.error("更新密码错误(大多可能因为是新密码跟原来相同引起)" + email);
        }
    }

    /**
     * 測試一個用戶的密碼和給定的密碼是否一樣（密碼是被哈希過的）
     * @param uuid
     * @param passwordHash
     * @return
     */
    public static boolean isPasswordMatch(String uuid, String passwordHash) {
        MongoCollection<Document> collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfUser);
        FindIterable<Document> findIterable = collection.find(Filters.eq("uuid", uuid)).projection(Projections.include("password"));
        MongoCursor<Document> cursor = findIterable.iterator();

        String passwordHa = "";
        if (cursor.hasNext()) {
            Document doc = cursor.next();
            passwordHa = doc.get("password").toString();
        }

        return passwordHash.equals(passwordHa);
    }

    /**
     * 更新一個用戶的密碼，uuid用來識別用戶
     * @param uuid
     * @param newPassword
     */
    public static void updatePasswordFromUUID(String uuid, String newPassword) {
        MongoCollection<Document> collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfUser);
        Bson filter = new Document("uuid", uuid);
        Bson newValue = new Document("password", newPassword);
        Bson updateOperationDocument = new Document("$set", newValue);
        UpdateResult result = collection.updateOne(filter, updateOperationDocument);
        if (result.getModifiedCount() != 1) {
            Logman.error("更新密码发生错误：" + uuid);
        }
    }

    /**
     * 得到所有用的uuid，返回一个列表（每个元素都是string）
     * @return
     */
    public static List<String> getAllUserUUID() {
        List<String> result = new ArrayList<>();

        MongoCollection<Document> collection = DatabaseMan.Instance().GetCollection(GlobalConfig.collectionNameOfUser);
        List<Document> documentList = collection.find().projection(Projections.include("uuid")).into(new ArrayList<>());

        for (int i = 0; i < documentList.size(); ++i) {
            String uuid = documentList.get(i).get("uuid").toString();
            result.add(uuid);
        }

        return result;
    }
}
